(function($){
	$.fn.extend({
		/**
		 * jquery plugins
		 * @功能：根据指定url加载页面代码到指定位置
		 * @作者：lj
		 * @日期：20170406
		 */
		//options= {
		//	"url":"",
		//  "data":"",
		//  "type":"",
		//  "preLoadPage":function(xhr){},
		//  "successLoaded":function(data,status,xhr){},
		//  "errorLoadPage":function(xhr,textStatus,errorThrown){},
		//  "completeLoadPage":function(){},
		//  "handleHtml":function(html){ return html;}
		//}
		// $(".xxx").loadPage(options);
		loadPage:function(options){
			// 校验url
			if(options.url == ctx){
				return ;
			}
			var params = options.data || "";
			var type = options.type || "get";
			// 支持跨域请求
			if(options.url.startsWith('http://')){
				options.dataType='jsonp';
			} else {
				options.dataType = 'text';
			}
			if(options.url=="/" || $.trim(options.url)==""){
				Logger.info("不能打开url路径为'/' 或 ''的页面");
				// MsgBox.error("无法打开此页面");
				return ;
			}
			// 输出HTML文档的方法
			var _this = this;
			var outputHtml = function(data){
				var $article = $();
				$(data).each(function(){
					var tagName = $(this).prop("tagName");
					if(tagName) {
						if($(this).attr("data-appendToBody")!="false" && $(this).attr("data-appendToBody")){
							$("body").append($(this));
						}else{
							$article = $article.add($(this));
						}
					}
				});
				_this.empty().append($article);
			};
			// 判断是否缓存有页面数据，尝试从缓存中取
			options.data || (options.data = {}); 
			if(options.data[options.url] != null){
				var data = options.data[options.url];
				outputHtml(data);
				return ;
			}
			MsgBox.startLoading();
			$.ajax({
				async:options.async == undefined ? true : options.async,
				url:options.url,
				type:type,
				"data":params,
				dataType:options.dataType || "text",
				jsonp:'callback',
				jsonpCallback:"success_jsonpCallback",
				success:function(data,status,xhr){
					try{
						var html = options.handleHtml && handleHtml(data);
						html ? outputHtml(html) : outputHtml(data);
					}catch(e){
						Logger.error(e);
					}
					MsgBox.stopLoading();
					options.successLoaded && options.successLoaded(data,status,xhr);
				},
				complete:function(){
					MsgBox.stopLoading();
					options.completeLoadPage && options.completeLoadPage();
				},
				beforeSend:function(xhr){
					options.preLoadPage && options.preLoadPage(xhr);
				},
				error: function(xhr,textStatus,errorThrown) {
					options.errorLoadPage && options.errorLoadPage(xhr,textStatus,errorThrown);
					Logger.error('you encountered an error while sending ajax');
					Logger.error(errorThrown);
					$.messager.error("错误：加载页面失败",{
						'placement':"center"
					});
					MsgBox.stopLoading();
				}
			});
		},
		/* {url,descHeight,onReadyStateChanged($iframe),iframeAttr} */
        loadPageByIframe:function(options) {
        	var opt = {};
        	$.extend(opt, options);
        	var $iframe = $("<iframe></iframe>");
        	var attr = {
        		'src':opt.url,
        		'width':'100%',
        		'height':opt.height ,
        		'scrolling':"auto",
        		'data-id':'D_' + $.uuid()
        	};
        	attr = $.extend(attr, opt.iframeAttr);
        	$iframe.attr(attr);
        	this.append($iframe);
        	$iframe.load(function() {
        		opt.onReadyStateChanged && opt.onReadyStateChanged($iframe);
        	});
        },
		/**
		 * jquery plugins
		 * @功能：tab set
		 * @作者：lj
		 * @日期：20170406
		 */
		//options = {
		//  "$parentBody":$("#serviceInQuiryDiv"),
		//	"preClose":function(){ // 关闭页面之前执行的方法
		//	},
		//	"preOpen":function(){ // 打开页面之前执行的方法
		//	},
		//	"preActiveTab":function(){ // 激活某个标签页之前执行的方法
		//	}
		//}
		tabset:function(options){
			var _this = this;
			// 初始化options.$body
			options.$body = $(this.data("tab-toggle"));
			options.$body.attr({
				"data-active":false
			});
			// console.log("enter");
			// on tab close event
			// steps of close tab：
			// 1. set $tabBody attribute: data-active=false
			// 2. set $tab attribute: data-active=false, data-join=false
			// 3. 判断是否所有$tab的attribute[data-join]都为false，若是，设置$tabContainer的data-active=false,
			//       同时设置$parentBody.show()
			var onTabClose = function(e, $tab, id){ // e:click event, id:$tab的id
				$tab.attr({
					"data-active":false,
					"data-join":false
				});
				var $tabBody = options.$body.find(".m-bodyset>.m-tab-body[data-id='"+ id +"']");
				$tabBody.attr({
					"data-active":false
				});
				if(_this.data("tab-single-body")) $tabBody.remove(); // when single body is true, remove $tabBody
				if( options.$body.find(".m-tabset>.m-tab-body[data-join='true']").length ==0 ){
					options.$body.attr("data-active",false);
					options.$parentBody.show();
				}
				e.stopPropagation();
				e.preventDefault();
			};
			// build tab set
			var buildTabSet = function(){
				if(options.$body.find(".m-tabset").length > 0){
					options.$body.find(".m-tabset").remove();
				}
				var $tabset = $("<div class='m-tabset'></div>");
				var $ul = $("<ul/>");
				$.each(options.data,function(index, item){
					var $li = $("<li/>");
					$li.addClass("m-tab");
					$li.attr({
						"data-id":item.id,
						"data-join":false,
						"data-active":false
					});
					var $a = $("<a/>");
					$a.attr({
						"data-title":item.title,
						"data-url":item.url,
						"href":item.url,
						"title":"点击刷新"
					});
					var $i = $("<i class='fa fa-fw fa-times-circle'/>");
					$a.append($i);
					$i.after(item.title);
					// 绑定关闭事件
					$i.off('click').on('click',function(e){
						onTabClose(e, $li, item.id);
					});
					// 绑定$a点击事件
					$a.off('click').on('click',function(e){
						e.stopPropagation();
						e.preventDefault();
						// 刷新页面
						var $tabBody = options.$body.find(".m-bodyset>.m-tab-body[data-id='"+ item.id +"']");
						$tabBody.empty().loadPage({
							"url":item.url
						});
					});
					$li.append($a);
					$ul.append($li);
				});
				$tabset.append($ul);
				return $tabset;
			};
			var buildBodySet = function(){
				if(options.$body.find(".m-bodyset").length == 0){
					var $bodyset = $("<div class='m-bodyset'></div>");
					return $bodyset;					
				}
				return options.$body.find(".m-bodyset");
			};
			
			var loadTabSetData = function(){
				var data = new Array();
				$.each(_this,function(index, btn){
					var url = $(this).data('tab-url');
					var title = $(this).data('tab-title');
					var id = $(this).data('tab-id');
					data.push({
						"id":id,
						"url":url,
						"title":title,
						"active":false,
						"join":false
					});
				});
				return data;
			};
			var getTabDataById = function(id){
				var mItem = null;
				$.each(options.data,function(index,item){
					if(item.id == id){
						mItem = item;
					}
				});
				return mItem;
			};
			var joinTab = function(id){
				// 1. 隐藏父布局
				options.$parentBody.hide();
				// 2. 显示tabContainer
				options.$body.attr({
					"data-active":true
				});
				// 使数据先变化
				var mItem = getTabDataById(id);
				mItem["join"]=true;
				// 变化DOM
				options.$body.find(".m-tab[data-id='"+ id +"']").attr({
					"data-join":true
				});
			};
			var activeTab = function(id,reload){
				// 使数据先变化
				$.each(options.data,function(index,item){
					item["active"] = false;
				});
				var mItem = getTabDataById(id);
				mItem["join"]=true;
				// 变化DOM
				options.$body.find(".m-tab[data-active='true']").attr("data-active",false);
				options.$body.find(".m-tab[data-id='"+ id +"']").attr("data-active",true);
				// body
				var $bodyset = options.$body.find(".m-bodyset");
				// 查找是否存在此body，存在则显示，不存在则输出
				var $tabBody = null;
				$tabBody = $bodyset.find(".m-tab-body[data-id='"+ id +"']");
				$bodyset.find(".m-tab-body[data-active='true']").attr("data-active",false);
				// if not exist body, then output body and set attribute: data-active=true
				if($tabBody.length == 0) {
					$tabBody = $("<div/>");
					$tabBody.attr({
						"data-id":id,
						"class":"m-tab-body",
					});
					$bodyset.append($tabBody);
				}
				if(reload){
					// reload page
					$tabBody.loadPage({
						"url":mItem.url,
						"successLoaded":function(data,status,xhr){
							$tabBody.attr("data-active",true);
						},
						"errorLoadPage":function(xhr,textStatus,errorThrown){
							$tabBody.attr("data-active",true);
						},
						"completeLoadPage":function(){
							$tabBody.attr("data-active",true);
						}
					});
				}
			};
			// 1. 装载tabset数据
			options.data = loadTabSetData();
			// 2. 输出tabset
			options.$body.append(buildTabSet());
			// 3. 输出bodyset
			options.$body.append(buildBodySet());
			
			$.each(this,function(index, btn){
				$(btn).off('click').on('click',function(e){
					// 根据id激活tab
					var id = $(this).data("tab-id");
					// join tab
					joinTab(id);
					// active tab
					activeTab(id, true);
				});
			});
		},
		/**
		 * jquery plugins
		 * @功能：下拉列表
		 * @作者：lj
		 * @日期：20170411
		 */
		// options = {
//	 	"triggerBtn":$("#searchBtn"), // 非必须
//	 	"onRenderItem":function(index,item,$a){ // 非必须
//	 		return $a;
//	 	},
//	 	"contentDefine":{
//	 		"id":"searchId",
//	 		"text":"showTitle"
//	 	},
//	 	"ajaxSetting":function(){
//	 		return {
//	 			"type":"GET",
//	 			"url":"sms/platform/search/"+escape($("input[name='searchKey']").val()),
//	 			"success":function(data,status,xhr){
//	 			}
//	 		};
//	 	},
//	 	"cssClass":"t-search-droplist",
	//  "silent":false, // 非必须
	//  "autocomplete":false, // 非必须
	//  "keySupport":false, // 非必须
	//  "timeout":150, // 非必须，默认150ms
	//  "onEnterKeyDown":function(val){}, // 敲Entere键触发的事件
	//  "onOutputErrorContent":function($container){}  // 请用$container拼接DOM或者返回待拼接的$DOM
	//  "onItemClick": function(e) {} // 点击事件
	// }
		dropList:function(options){
			var DEFAULT_EMPTY_PROMPT = "没有找到查询结果";
			var TIME_OUT = 200;
			
			var $this = this;
			var $mInput = options.input;
			var $mTriggerBtn = options.triggerBtn;
			var onRendItemFunc = options.onRenderItem;
			var ajaxSetting = options.ajaxSetting;
			var contentDefine = options.contentDefine;
			var onItemClick = options.onItemClick;
			var silent = options.silent;
			var cssClass= options.cssClass;
			var emptyPrompt = options.emptyPrompt || DEFAULT_EMPTY_PROMPT;
			var keySupport = options.keySupport || false;
			var timeout = options.timeout || TIME_OUT;
			var onEnterKeyDown = options.onEnterKeyDown;
			var onOutputErrorContent = options.onOutputErrorContent;
			
			// 输出列表内容
			var outputList = function(data){
				// 清空内容
				$this.parent().find(".m-drop-list").remove();
				$this.parent().find(".error-prompt").remove();
				// 发送ajax请求，输出内容
				var $ul = $("<ul/>");
				$ul.on('mouseleave blur',function(){
					removeDropList();
				});
				$ul.addClass("m-drop-list m-ul-pure");
				cssClass && $ul.addClass(cssClass);
				$.each(data,function(index, item){
					var $li = $("<li/>");
					$li.addClass("drop-item");
					$li.attr({
						"data-id":(contentDefine.id ? item[contentDefine.id] : "")
					});
					var $itemDom = $(itemDom);
					$li.append($itemDom);
					// 默认模式
					var $a = $("<a/>");
					$a.attr({
						"href":item.url,
					});
					$a.on('click',function(e){
						onItemClick && onItemClick(e);
						removeDropList();
					});
					contentDefine.text && $a.text(item[contentDefine.text]);
					var itemDom = onRendItemFunc && onRendItemFunc(index,item,$a);
					if(itemDom) $li.append(itemDom);
					else $li.append($a);
					$ul.append($li);
				});
				$this.after($ul);
				$ul.css("display","none");
				$ul.slideDown(200);
				$ul.focus();
			};
			// 移除下拉错误框
			var removeErrorContent = function(){
				$this.parent().find(".error-prompt").slideUp(200);
				setTimeout(function(){
					$this.parent().find(".error-prompt").remove();
				},200);
			};
			// 移除下拉列表
			var removeDropList = function(){
				$this.parent().find(".m-drop-list").slideUp(200);
				setTimeout(function(){
					$this.parent().find(".m-drop-list").remove();
				},200);
			};
			// 移除所有下拉
			var removeDrop = function() {
				removeDropList();
				removeErrorContent();
			};
			// 输出错误内容
			var outputErrorContent = function(errorText){
				$this.parent().find(".m-drop-list").remove();
				$this.parent().find(".error-prompt").remove();
				var $errorContent = $("<p></p>");
				$errorContent.addClass("error-prompt");
				if (onOutputErrorContent) {
					var $dom = onOutputErrorContent($errorContent, errorText);
					$dom && $errorContent.append($dom);
				} else {
					$errorContent.text(errorText);
				}
				$errorContent.on('mouseleave blur',function(e){
					removeErrorContent();
				});
				$this.after($errorContent);
			};
			// 处理回车和搜索按钮点击事件
			var handle = function($dom, val){
				var _ajaxSetting = null;
				if(typeof ajaxSetting=="function"){
					_ajaxSetting = ajaxSetting();
				}
				if(_ajaxSetting && _ajaxSetting.url){
					var mAjaxSetting = {
						success:_ajaxSetting.success,
						error:_ajaxSetting.error,
						complete:_ajaxSetting.complete,
						beforeSend:_ajaxSetting.beforeSend
					};
					_ajaxSetting.success = function(data,status,xhr){
						$.sessionTimeoutHandle(xhr, status);
						
						Logger.info("=>" + JSON.stringify(data));
						if(typeof data =="string"){
							data = JSON.parse(data);
						}
						if(data.success) {
							// data.info 返回List
							// data.info.data => 分页查询数据
							var mData = null;
							if (data.info && data.info instanceof Array && data.info.length > 0) mData = data.info;
							if (data.info.data && data.info.data instanceof Array && data.info.data.length>0) mData = data.info.data;
							if (mData){
								outputList(mData);
							} else {
								outputErrorContent(emptyPrompt);
							}
						}
						mAjaxSetting.success && mAjaxSetting.success(data,status,xhr);
						options.silent || MsgBox.stopLoading();
					};
					_ajaxSetting.error = function(xhr,textStatus,errorThrown){
						outputErrorContent(emptyPrompt);
						Logger.info("=>" + JSON.stringify(textStatus));
						mAjaxSetting.error && mAjaxSetting.error(xhr,textStatus,errorThrown);
						options.silent || MsgBox.stopLoading();
					};
					_ajaxSetting.complete = function(XMLHttpRequest, textStatus){
						/*var data=request.responseJSON;
						if(data.ret!=null&&data.ret==302){//根据服务器端返回的数据判断
							window.location=data.redirectUrl;
						}
*/
						$.sessionTimeoutHandle(XMLHttpRequest, textStatus);
						mAjaxSetting.complete && mAjaxSetting.complete(event,request, settings);
						options.silent || MsgBox.stopLoading();
					};
					_ajaxSetting.beforeSend = function(xhr){
						mAjaxSetting.beforeSend && mAjaxSetting.beforeSend(xhr);
					};
					
					!silent && MsgBox.startLoading();
					
					var lastTime = $this.data("time") || 0;
					var currTime = (new Date()).getTime();
					if (currTime - lastTime < timeout) {
						// 清除上次的定时器
						var timeOutId = $this.data("timeout-id");
						clearTimeout(timeOutId);
					}
					var timeOutId = setTimeout(function(){
						$.ajax(_ajaxSetting);
					}, timeout);
					$this.data("timeout-id", timeOutId);
					$this.data("time", currTime);

				} else {
					if(options.data && options.data instanceof Array && options.data.length>0) outputList(options.data);
					else outputErrorContent(emptyPrompt);
				}
			};
			// 绑定按键事件
			$this.on("keydown",function(e){
				Logger.warn("e.which = - " + e.which);
				var code = e.which;
				if(code == 27){ // Esc
					$this.val("");// 清空内容
					$this.parent().find(".m-clear-btn").remove();
				} else if(code == 13){ // 回车
					var key = "droplist-100001";
					if(!MsgBox.preventViolentClick(key,"",500,false)){
						if (onEnterKeyDown) {
							var mDoneOpt = onEnterKeyDown($(this).val());
							if (mDoneOpt) {
								if (mDoneOpt.doRemove) {
									removeDrop();
								}
							}
						} else {
							Logger.info("执行请求");
							handle($(this),$(this).val());
						}
					};
				} else if (code == 40) { // ↓
					
				} else if (code == 38) { // ↑
					
				}
				e.stopPropagation();
			});
			$this.bind('input propertychange',function(e){
				var len = $this.val().length;
				if(len > 0){
					if( $this.parent().find(".m-clear-btn").length==0){
						var $clearBtn = $("<i class='fa fa-fw fa-times-circle m-clear-btn'/>");
						$clearBtn.on('click',function(e){
							$this.val("");
							$this.parent().find(".m-clear-btn").remove();
							$this.focus();
						});
						$this.after($clearBtn);
					}
					options.autocomplete && $this && handle($this,$this.val());
				} else {
					$this.parent().find(".m-clear-btn").remove();
					$this.parent().find(".m-drop-list").remove();
					$this.parent().find(".error-prompt").remove();
				}
			});
			$this.on("focus",function(e){
				removeDropList();
			});
			// 绑定点击事件
			$mTriggerBtn && $mTriggerBtn.on("click",function(e){
				$this && handle($this,$this.val());
			});
		},
		// 时间轴
		/*$(".m-timeline").timeline({
			"data":[],
			"contentDefine":{
				"id":"id",
				"time":"",
				"date":"",
				"content":""
			},
			// 定义你的内容主体，返回值可有可无，你可以考虑用$container去append你的内容，
			// 也可以让插件append你返回的内容，前提是你返回的必须是一个jquery对象
			"contentBody":function($container,item){
				$container.append($xxx);
				// var $content=...;
				// return $content;
			}
		});*/
		timeline:function(options){
			var $this = this;
			var contentDefine = options.contentDefine || {};
			var cssClass= options.cssClass;
			var data = options.data || [];
			// 输出列表内容
			var outputList = function(data){
				// 清空内容
				$this.find("ul.m-timeline").empty();
				// 发送ajax请求，输出内容
				var $ul = $("<ul/>");
				$ul.addClass("m-timeline");
				cssClass && $ul.addClass(cssClass);
				$.each(data,function(index, item){
					var $li = $("<li/>");
					$li.attr({
						"data-id":(contentDefine.id ? item[contentDefine.id] : "")
					});
					var $timeWrapper = $("<div class='time-wrapper'/>");
					var $date = $("<time class='date'/>");
					contentDefine.date && $date.text(item[contentDefine.date]);
					$timeWrapper.append($date);
					var $time = $("<time class='time'/>");
					contentDefine.time && $time.text(item[contentDefine.time]);
					$timeWrapper.append($time);
					
					var $content = $("<div class='content'/>");
					contentDefine.content && $content.text(item[contentDefine.content]);
					
					if(options.contentBody && options.contentBody instanceof Function){
						var $contentBody = options.contentBody($content,item);
						$contentBody && $content.append($contentBody);
					}
					
					$li.append($timeWrapper);
					$li.append($content);
					
					$ul.append($li);
				});
				$this.append($ul);
				/*$ul.css("display","none");
				$ul.slideDown(200);*/
				$ul.focus();
			};
			// 输出错误内容
			var outputErrorContent = function(errorText){
				$this.find(".error-prompt").remove();
				var $errorContent = $("<p></p>");
				$errorContent.addClass("error-prompt");
				$errorContent.text(errorText);
				var removeErrorContent = function(){
					$this.parent().find(".error-prompt").slideUp(200);
					setTimeout(function(){
						$this.parent().find(".error-prompt").remove();
					},200);
				};
				$errorContent.on('mouseleave blur',function(e){
					removeErrorContent();
				});
				$this.append($errorContent);
			};
			if(data && data.length > 0){
				outputList(data);
			} else {
				outputErrorContent("没有查询到内容");
			}
		},
		/**
		 * jquery plugins
		 * @功能：构造加载中状态
		 * @参数：
		 * <p>iconSize,</p>
		 * @作者：lj
		 * @日期：2017-06-02 
		 * @调用：tree.tag
		 */
		startLoading:function(options) {
			var LOADER_ID = 'loader';
			var $loader = this.find('#' + LOADER_ID);
			if ($loader.length <= 0) {
				var opt = {
					'iconSize':3
				};
				opt = $.extend(opt, options);
				$loader = $("<div/>");
				$loader.attr({
					'id':LOADER_ID,
					'class':'m-loader'
				});
				var $icon = $('<i/>');
				$icon.attr('class','icon icon-spin icon-spinner-indicator');
				$icon.addClass('icon-' + opt.iconSize + 'x');
				$loader.append($icon);
				this.append($loader);
			}
		},
		stopLoading: function(options) {
			var LOADER_ID = 'loader';
			var $loader = this.find('#' + LOADER_ID);
			$loader.remove();
		},
		/**
		 * jquery plugins
		 * @功能：自动填充表单
		 * @参数：
		 * <p>data, {clearHidden}</p>
		 * @作者：lj
		 * @日期：2017-07-02 
		 */
		autofill: function(data, options) {
			var settings = {
				findbyname: true,
				restrict: true,
				clearHidden: true,
				formObj: false
			},
			self = this;
			if ( options ) {
				$.extend( settings, options );
			}
			
			this.clearForm(settings.clearHidden); // 清空表单里面的值，包含隐藏表单的值
			
			if (settings.formObj) {
				data = $.formObj(data);
			}
			var autofill = function(k, v) {

				// switch case findbyname / findbyid
				v = Util.htmlDecode(v); // 将value值解码
				var selector, elt;
				if ( settings.findbyname ) { // by name
					selector = '[name="'+k+'"]';
					elt = ( settings.restrict ) ? self.find( selector ) : $( selector );
					if ( elt.length == 1 ) {
						elt.val( ( elt.attr("type") == "checkbox" ) ? [v] : v );
					} else if ( elt.length > 1 ) {
						// radio
						elt.val([v]);
//						ele.find("value="+v).prop("checked",true);
					} else {
						selector = '[name="'+k+'[]"]';
						elt = ( settings.restrict ) ? self.find( selector ) : $( selector );
						elt.each(function(){
							$(this).val(v);
						});
					}
				} else { // by id
					selector = '#'+k;
					elt = ( settings.restrict ) ? self.find( selector ) : $( selector );
					
					if ( elt.length == 1 ) {
						elt.val( ( elt.attr("type") == "checkbox" ) ? [v] : v );
					} else {
						var radiofound = false;
						// radio
						elt = ( settings.restrict ) ? self.find( 'input:radio[name="'+k+'"]' ) : $( 'input:radio[name="'+k+'"]' );
						elt.each(function(){
							radiofound = true;
							if ( this.value == v ) { this.checked = true; }
						});
						// multi checkbox
						if ( !radiofound ) {
							elt = ( settings.restrict ) ? self.find( 'input:checkbox[name="'+k+'[]"]' ) : $( 'input:checkbox[name="'+k+'[]"]' );
							elt.each(function(){
								$(this).val(v);
							});
						}
					}
				}
			};
			
			return this.each(function() {
				$.each( data, function(k, v) {
					autofill(k, v);
				});
			});
		},
		/**
		 * 多层级表单验证
		 * @param emptyText:当表单内容为空时的提示
		 * @param validateChain:[{validateFunc,errorText,params[(3)]}...] 验证链条，validateFunc一定是公共的验证方法
		 */
		simpleValidate:function(emptyText, validateChain) {
			var $this = this;
			var val = this.val();
			if (StringUtil.isBlank(val)) {
				MsgBox.warn(emptyText, null, function(){
					$this.focus();
				});
				return false;
			}
			
			var executeChain = function() {
				var error = false;
				for (var i = 0; i < validateChain.length; i++ ) {
					var item = validateChain[i];
					
					if (StringUtil.isString(item.validateFunc)) {
						item.validateFunc = eval(item.validateFunc);
					}
					
					var rs = item.validateFunc(val, item.params[0], item.params[1], item.params[2]);
					
					if (!rs) {
						error = true;
						MsgBox.warn(item.errorText, null, function() {
							$this.focus();
						});
						break;
					}
				}
				if (error) {
					return false;
				}
				return true;
			};
			return executeChain();
		},
		/**
		 * jquery plugins
		 * @功能：列出标签块
		 * @参数：
		 * <p>contentDefine{text,id},edit,remove,view,data,onRemove(e,item),onEdit(e,item),onView(e,item),emptyText,afterBuild,beforeBuild,css{border}</p>
		 * @作者：lj
		 * @日期：2017-06-02 
		 */
		listTags:function(options) {
			this.empty();
			var opt = {
				'edit':false,
				'remove':false,
				'view':false,
				'contentDefine':{
					'id':'id',
					'text':'text'
				},
				'emptyText':'没有数据',
				'css':{
					'border':'1px solid #EEE'
				}
			};
			$.extend(opt,options);
			var contentDefine = opt.contentDefine;
			var css = opt.css;
			var that = this;
			var ICON_SET = {
				'edit':'fa fa-edit',
				'view':'fa fa-eye-open',
				'remove':'fa fa-times'
			};
			// 记录所有标签
			opt.allTagInfos = new GenericSet(opt.data);
			var recorder = new Recorder();
			
			var $container = $("<div class='m-tags'/>");
			$container.css(css);
			opt.beforeBuild && opt.beforeBuild(this);
			// 方法申明 - 构造tag项
			var buildTagItem = function(item) {
				var $tag = $("<a class='m-tag'/>");
				$tag.attr({
					'data-id':item[contentDefine.id],
					'data-text':item[contentDefine.text]
				});
				$tag.text(item[contentDefine.text]);
				if (opt.edit) {
					var $icon = $("<i/>").addClass(ICON_SET['edit']);
					$icon.on('click',function(e){
						opt.onEdit && opt.onEdit(e, item);
					});
					$tag.append($icon);
				}
				if (opt.remove) {
					var $icon = $("<i/>").addClass(ICON_SET['remove']);
					$icon.on('click',function(e){
						$tag.remove();
						opt.onRemove && opt.onRemove(e, item);
					});
					$tag.append($icon);
				}
				if (opt.view) {
					var $icon = $("<i/>").addClass(ICON_SET['view']);
					$icon.on('click',function(e){
						opt.onView && opt.onView(e, item);
					});
					$tag.append($icon);
				}
				return $tag;
			};
			// 方法申明 - 构造内容为空时的标签
			var buildEmptyText = function() {
				var $empty = $("<p class='m-empty-text'></p>");
				if (ObjectUtil.isFunction(opt.emptyText)) {
					$empty.append(opt.emptyText());
				} else {
					$empty.text(opt.emptyText);
				}
				return $empty;
			};
			
			// 具体业务流程
			if (ArrayUtil.hasData(opt.data)) {
				$.each(opt.data, function(index, item) {
					var $tag = buildTagItem(item);
					$container.append($tag);
				});
			} else {
				$container.append(buildEmptyText());
			}
			that.append($container);
			opt.afterBuild && opt.afterBuild(this);
			return {
				// 判断是否存在用户操作
				'hasOperate':function() {
					return recorder.hasOperate();
				},
				'getRecorder':function(){
					return recorder;
				},
				'getAllTagInfos':function() {
					return opt.allTagInfos.arr;
				},
				// item:要新增的数据，key:用于对象数组中做比较的字段，func:当opt.allTagInfos中已存在item时的回调
				'addItem':function(item, key, func) {
					key = key || contentDefine.id;
					if (!opt.allTagInfos.hasData()) {
						$container.find('.m-empty-text').remove();
					}
					if (!opt.allTagInfos.hasItemOfKey(item, key)) {
						var $tag = buildTagItem(item);
						$tag.highlight({
							'timeout':500
						});
						$container.append($tag);
					} else {
						func && func();
					}
					this.getRecorder().getNewRecords().putByKey(item, key);
					opt.allTagInfos.putByKey(item, key);
				},
				// item:要删除的数据，key:用于对象数组中做比较的字段，func:当删除到为空时的回调
				'deleteItem':function(item, key,func) {
					key = key || contentDefine.id;
					this.getRecorder().getDeleteRecords().putByKey(item, key);
					opt.allTagInfos.removeByKey(item, key);
					if (!opt.allTagInfos.hasData()) {
						$container.append(buildEmptyText());
						func && func();
					}
				},
				'updateItem':function(item, key) {
					key = key || contentDefine.id;
					this.getRecorder().getUpdateRecords().putByKey(item, key);
					opt.allTagInfos.putByKey(item, key);
				}
			};
		},
		/**
		 * jquery plugins
		 * @功能：文本强调
		 * @作者：lj
		 * @日期：20170517
		 */
		highlight:function(options) {
			var opt = {
				'className': 'm-highlight',
				'timeout': 1000
			};
			opt = $.extend(opt, options);
			var $this = this;
			this.addClass(opt.className);
			setTimeout(function(){
				$this.removeClass(opt.className);
			}, opt.timeout);
		},
		/**
		 * jquery plugins
		 * @作者:lj
		 * @参数：{data,contentDefine{key,value},onItemClick,defaultIndex,delete,onDelete,defalutId}
		 * @日期：20170322
		 * @功能:aside 侧边栏
		 */
		aside:function(options){
			var opt = {
				'defaultIndex':0,
				'delete':false,
				'contentDefine':{
					'key':'key',
					'value':'value'
				},
			};
			$.extend(opt, options);
			this.attr({
				'data-part':'menu'
			});
			// 先清空
			this.empty();
			var contentDefine = opt.contentDefine;
			// 定义单个菜单项构建
			var buildMenuItem = function($ul, item, i) {
				var key = item[contentDefine.key];
				var value = item[contentDefine.value];
				var $item = $("<li><a href='javascript:void(0);'></a></li>");
				var $link = $item.find("a");
				$link.attr("data-value", key);
				$link.attr("data-text", value);
				if (i == null) {
					i = $ul.find("li").length;
				}
				$link.attr("data-index", i);
				var $text = $("<span></span>");
				$text.text(value);
				$link.append($text);
				$link.on('click', function(e){
					e.stopPropagation();
					e.preventDefault();
					// 激活菜单
					var prevent = opt.onItemClick && opt.onItemClick(item, $(this));
					if (!prevent) {
						$ul.find("li.active").removeClass("active");
						$(this).closest("li").addClass("active");
					}
				});
				if (opt['delete']) {
					var $delBtn = $("<i class='fa fa-fw fa-times-circle' data-type='delete'/>");
					$link.append($delBtn);
					$delBtn.on('click', function(e) {
						e.stopPropagation();
						e.preventDefault();
						opt.onDelete && opt.onDelete(key, value);
					});
				}
				return $item;
			};
			// 定义菜单构建
			var buildMenu = function() {
				var $ul = $("<ul/>");
				var i = 0;
				$.each(opt.data, function(index, item) {
					var $item = buildMenuItem($ul, item, i++);
					$ul.append($item);
				});
				return $ul;
			};
			
			// 1.构建左侧菜单
			var $menu = buildMenu();
			// 2.选中默认，defaultIndex / defaultId
			if (opt.defaultId) {
				$($menu.find("li>a[data-value='" + opt.defaultId + "']")).click();
			} else {
				$($menu.find("li>a")[opt.defaultIndex]).click();
			}
			
			this.append($menu);
			
			var mAside = {
				'addNode':function(obj) {
					if (obj == null) {
						throw new Error("新增节点的信息不能为空");
					}
					var $item = buildMenuItem($menu, obj);
					$menu.append($item);
					// 激活创建的新节点
					var index = $item.find("a").data('index');
					$($menu.find("li>a")[index]).click();
				},
				'updateCurrentText':function(text) {
					$menu.find("li.active>a>span").text(text);
				}
			};
			$.extend(mAside, opt);
			return mAside;
		},
		/**
		 * jquery plugins
		 * @作者:lj
		 * @参数：{url,articleContentDefine,data,onItemClick(e,item),handleData,onQueryArticleSuccess(data,status,xhr),onQueryArticleError(xhr,textStatus,errorThrown)}
		 * @日期：20170322
		 * @功能:aside 构建文章
		 */
		article:function(options) {
			var opt = {
				'ajaxSetting':{
					'type':'get',
					'data':null,
					'dataType':'json',
					'contentType':'application/json'
				},
				'contentDefine':{
					"title":"title", /* 标题 */
					"target":"target", /* 目标网页，超链接 */
					"summary":"summary", /* 内容概述 */
					"id":"id", /* id */
					"notes":[
					     {"text":"更新时间","key":"updateTime"}
					 ], /* 脚注 */
				}
			};
			$.extend(opt, options);
			var $this = this;
			
			// 1. 清空先前的内容
			this.empty();
			// 定义输出错误时的内容
			var outputErrorContent = function(msg,color){
				var $contentDiv = $("<h2></h2>");
				$contentDiv.text(msg);
				$contentDiv.css({
					"color": (color || "#C00"),
					"text-align":"center",
					"border":"1px dotted #CCC",
					"line-height":"100px",
					"-webkit-user-select":"none",
					"-moz-user-select":"none",
					"-o-user-select":"none",
					"user-select":"none",
				    "font-size": "1.5em",
					"font-weight": "bold"
				});
				$this.append($contentDiv);
			};
			
			// 2.输出文章
			var outputArticleList = function(data){
				var list = data.info;
				var contentDefine = opt.contentDefine;
				if(!list || !list.length){
					outputErrorContent("抱歉，没能为你找到相关内容，换个关键字试试！","#999");
				}
				$.each(list,function(index,item){
					var $article = $("<div class='t-article'></div>");
					
					// 添加data-id属性唯一标识
					$article.attr("data-id",item[contentDefine.id]);
					
					// 拼接操作栏
					var $optBar = $("<div class='opt-bar'></div>");
					if(opt.optBar){
						$optBar.append(opt.optBar);
					}
					$article.append($optBar);
					
					// 拼接标题
					var $h2 = $("<h2><a></a></h2>");
					var $link = $h2.find("a");
					var href = "#";
					if(contentDefine && contentDefine.target && item[contentDefine.target]){
						href=item[contentDefine.target];
					}
					$link.attr({
						"href":href,
						"target":"_Blank"
					});
					$link.attr("data-text",item[contentDefine.title] || "#无标题");
					$link.text(item[contentDefine.title] || "#无标题");
					$link.off('click')
						.on('click',function(e){
							opt.onItemClick && opt.onItemClick(e,item);
						});
					$article.append($h2);
					
					// 拼接概述
					$summary = $("<p class='t-summary'></p>");
					$summary.text(item[contentDefine.summary] || "#无概述");
					$article.append($summary);
					// 拼接脚注
					$notes = $("<div class='t-foot-notes'></div>");
					var mNotes = contentDefine.notes;
					if(mNotes && mNotes.length>0){
						$.each(mNotes,function(noteIndex,note){
							$noteItem = $("<div class='m-form-group t-foot-note'></div>");
							var width = (100/mNotes.length) + "%";
							$noteItem.css({
								"width":width
							});
							// note name
							$noteName = $("<span class='t-note-name'></span>");
							var noteName = note.name || "#未命名";
							$noteName.text(noteName);
							// note value
							$noteValue = $("<span class='t-note-value'></span>");
							var noteValue = "#没有值";
							if(note.key){
								noteValue = item[note.key];
								$noteItem.attr("data-tag", note.key);
							}
							$noteValue.text(noteValue);
							$noteItem.append($noteName);
							$noteItem.append("&nbsp;&#58;&nbsp;");
							$noteItem.append($noteValue);
							$notes.append($noteItem);
						});
					}
					$article.append($notes);
					$this.append($article);
				});
			};
			var handle = function(data) {
				var mData = data;
				if(opt.handleData && ObjectUtil.isFunction(opt.handleData)){
					try{
						mData = opt.handleData(data);
					}catch(e){
						outputErrorContent("解析内容失败："+e.stack);
					}
				}
				if(!mData){
					outputErrorContent("糟糕X﹏X，获取内容失败！");
					return ;
				}
				if(mData.success=="true" || mData.success==true){
					outputArticleList(mData);
				} else {
					outputErrorContent(mData.message);
					return ;
				}
				// 执行注册的回调函数 onSuccess
				opt.onQueryArticleSuccess && opt.onQueryArticleSuccess(data,status,xhr);
			};
			if (!opt.url) {
				if (opt.data) {
					handle(opt.data);
				}
				return ;
			}
			opt.ajaxSetting.success = function(data, status, xhr) {
				handle(data);
			};
			opt.ajaxSetting.error = function(xhr,textStatus,errorThrown) {
				outputErrorContent("糟糕X﹏X，获取内容失败！");
				// 执行注册的回调函数 onError
				opt.onQueryArticleError && opt.onQueryArticleError(xhr,textStatus,errorThrown);
			};
			opt.ajaxSetting.url = opt.url;
			// 3.发送ajax请求数据
			$.mAjax(opt.ajaxSetting);
		},
		/**
		 * jquery plugins
		 * @param options {prompt}
		 * @returns
		 * TODO
		 */
		formValidate:function(options) {
			// input, textarea, select
			var opt = {
				'structure':{},
				'prompt':'dialog',
//				structure:{
//					'name':{
//				        'noteEmpty':true/false,
//				        'prompt':'dialog/messager'
//						'emptyText':'',
//						'validateChain':[
//						     {'errorText':'','validateFunc':function(){},'prompt':'dialog','params':[],'regexp':'','prevent':''}
//						 ]
//					}
//				}
			};
			$.extend(opt, options);
			
			var getDataValue = function(text) {
				return StringUtil.isBlank(text) ? null : text;
			};
			var getBooleanValue = function(text, defaultValue) {
				return ObjectUtil.isBoolean(text) ? text : text == 'true';
			};
			var getFunctionValue = function(funcName) {
				if (StringUtil.isBlank(funcName)) {
					return null;
				} else {
					var indexs = funcName.split(".");
					var x = window;
					for (var i = 0; i < indexs.length; i++) {
						x = x[indexs[i]];
					}
					return x;
				}
			};
			var getArrayValue = function(text) {
				if (StringUtil.isEmpty(text)) {
					return null;
				}
				var x = new Array(5);
				var y = eval(text);
				$.extend(y, x);
				return y;
			};
			
			// 取参数
			this.find("[data-validate='true']").each(function(){
				var $this = $(this);
				var type = $this.attr("type");
				var name = $this.attr("name");
				if (StringUtil.isBlank(name)) {
					return true;
				}
				
				if (type == 'checkbox') {
					
				} else if (type == 'radio') {
					
				} else {
					var item = {};
					
					var emptyText = $this.data('empty-text');
					var notEmpty = $this.data('not-empty');
					var prompt = $this.data('prompt');
					
					prompt = getDataValue(prompt);
					if (prompt != 'messager') {
						prompt = 'dialog';
					}
					
					item.prompt = prompt;
					item.notEmpty = getBooleanValue(notEmpty, false);
					item.emptyText = getDataValue(emptyText);
					item.value = $this.val();
					
					// 验证链，验证链中，errorText是必须的
					var validateChain = new Array();
					
					var i = 0;
					while (true) {
						var errorTextKey = i + '-error-text';
						
						var errorText = $this.data(errorTextKey);
						if (StringUtil.isBlank(errorText)) {
							break;
						}
						var regexpKey = i + '-regexp';
						var regexp = $this.data(regexpKey);
						
						var validateFuncKey = i + '-validate-func';
						var validateFunc = $this.data(validateFuncKey);
						
						var preventKey = i + '-prevent';
						var prevent = $this.data(preventKey);
						
						var paramsKey = i + '-params';
						var params = $this.data(paramsKey);
						
						var citem = {};
						citem['errorText'] = getDataValue(errorText);
						citem['regexp'] = getDataValue(regexp);
						citem['validateFunc'] = getFunctionValue(validateFunc);
						citem['prevent'] = getBooleanValue(prevent, true);
						citem['params'] = getArrayValue(params);
						validateChain[i] = citem;
						
						i ++;
					}
					
					item.validateChain = validateChain;
					opt.structure[name] = item;
				}
				
			});
			
			var prompt = function( promptWay, text, $dom) {
				if (promptWay == 'dialog') {
					MsgBox.info(text, null, function() {
						$dom.focus();
					});
				} else if (promptWay == 'messager') {
					$.messager.info(text);
					$dom.focus();
				}
			};
			
			var $frm = this;
			var validate = function() {
				if (!opt.structure) {
					return true;
				}
				$.each(opt.structure, function(key, item) {
					var value = item.value;
					var $dom = $frm.find("*[name='" + key + "']");
					if (item.notEmpty) {
						if (StringUtil.isEmpty(value)) {
							prompt(item.prompt, item.emptyText, $dom);
							opt.structure.validateResult = false;
							return false;
						}
					}
					// 当值为空时，不用再继续判断了，直接过掉，continue
					if (StringUtil.isEmpty(value)) {
						return true;
					}
					// continue
					var validateChain = item.validateChain;
					if (!ArrayUtil.hasData(validateChain)) {
						return true;
					}
					$.each(validateChain, function(index, citem) {
						var errorText = citem.errorText;
						var mprompt = citem.prompt;
						if (mprompt == null) {
							mprompt = item.prompt;
						}
						var validateFunc = citem.validateFunc;
						var params = citem.params;
						
						// regexp 优先
						var regexp = citem.regexp;
						if (regexp != null) {
							var reg = new RegExp(regexp);
							var testResult = reg.test(value);
							if (!testResult) {
								prompt(mprompt, errorText, $dom);
								opt.structure.validateResult = false;
								return false;
							}
						}
						
						// 执行验证函数
						if (validateFunc != null) {
							var result = false;
							if (ArrayUtil.hasData(params)) {
								result = validateFunc(value, params[0], params[1], params[2], params[3], params[4]);
							} else {
								result = validateFunc(value);
							}
							if (!result) {
								prompt(mprompt, errorText, $dom);
								opt.structure.validateResult = false;
								return false;
							}
						}
					});
				});
				if (opt.structure.validateResult == undefined) {
					return true;
				} else {
					return opt.structure.validateResult;
				}
			};
			
			// 1.从form中取参数
			// 2.验证
			return validate();
		}
	});
})(window.jQuery);